package com.raven.craft.code.generator.project.antijson.type;

import com.raven.craft.code.generator.common.constant.Constant;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.*;
import java.util.stream.Collectors;

@Getter
@Setter
@ToString
public class ObjectType implements Type, Mergeable {
    private String qualifiedName;
    private String name;
    private Map<String, Type> fields;

    public ObjectType(String qualifiedName, Map<String, Type> fields) {
        this.qualifiedName = qualifiedName;
        List<String> qualifiedNameList = Arrays.stream(qualifiedName.split(Constant.DELIMITER)).filter(s -> !s.equals(Constant.ANONYMOUS_NODE_NAME)).collect(Collectors.toList());
        this.name = qualifiedNameList.get(qualifiedNameList.size() - 1);
        this.fields = fields;
    }

    @Override
    public Set<String> getImports() {
        Set<String> set = fields.values()
                .stream()
                .map(Type::getImports)
                .flatMap(Collection::stream)
                .collect(Collectors.toSet());

        set.add("lombok.*");
        return set;
    }

    @Override
    public void merge(Type other) {
        ObjectType _other = (ObjectType) other;
        if (_other.getFields().isEmpty()) {
            // nothing to do
        } else if (this.getFields().isEmpty()) {
            this.setFields(_other.getFields());
        } else {
            _other.getFields().keySet()
                    .stream()
                    .filter(fieldName -> this.getFields().containsKey(fieldName))
                    .forEach(fieldName -> {
                        this.getFields().put(fieldName,
                                Type.reduce(this.getFields().get(fieldName), _other.getFields().get(fieldName)));
                    });

            _other.getFields().keySet()
                    .stream()
                    .filter(fieldName -> !this.getFields().containsKey(fieldName))
                    .forEach(fieldName -> {
                        this.getFields().put(fieldName,
                                _other.getFields().get(fieldName));
                    });
        }
    }
}